//
// Created by 王乐 on 2022/2/16.
//

#include "LeCubicSubBoxRenderer.h"
#include "glad/glad.h"

#include "LeVBOManager.h"
#include "LeUtils.h"

#include "LeCameraManager.h"

#include "glm/gtc/matrix_transform.hpp"
#include "LeScreenSettings.h"

#include "LeCameraFlyBehaviour.h"
#include "LeCameraCADBehaviour.h"

#include "LeCubicSubBoxGameObject.h"

#include "LeScene.h"

LeCubicSubBoxRenderer::LeCubicSubBoxRenderer()
{

}

LeCubicSubBoxRenderer::~LeCubicSubBoxRenderer()
{

}

void LeCubicSubBoxRenderer::preLoopRender()
{
    unsigned int VBO;
    LeVBOManager::findVBO("Cube", VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);
}

void LeCubicSubBoxRenderer::render()
{
    if(!m_GameObject->isActive())
        return;

    // projection
    // ----------
//    glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
    glm::mat4 projection = glm::ortho(-4.0f, 4.0f,
                                      -3.0f, 3.0f,
                                      0.1f, 15.0f);
    // view
    // ----
//    LeCameraFlyBehaviour* pCameraBehaviour = dynamic_cast<LeCameraFlyBehaviour*>(LeCameraManager::pCameraObject->m_pCameraBehaviour);
    LeCameraCADBehaviour* pCameraBehaviour = dynamic_cast<LeCameraCADBehaviour*>(LeCameraManager::pCameraObject->m_pBehaviour);

    glm::vec3 camerafront = pCameraBehaviour->Front;
    glm::vec3 cameraup = pCameraBehaviour->Up;
    glm::vec3 cameraright = pCameraBehaviour->Right;

    float distanse2focus = 10;
    glm::vec3 focus = glm::vec3(0,0,0);
    glm::vec3 curCameraposition = focus - distanse2focus * camerafront;

    float offsetx = -2.1;
    float offsety = 2.1;
    glm::vec3 curOffsetCameraposition = curCameraposition + offsetx * cameraright + offsety * cameraup;

    glm::mat4 view = glm::lookAt(curOffsetCameraposition,
                                 curOffsetCameraposition + camerafront,
                                 cameraup);


    // be sure to activate shader when setting uniforms/drawing objects
    m_Shader.useShader();

    m_Shader.setMat4("projection", projection);
    m_Shader.setMat4("view", view);

    glm::mat4 model = m_GameObject->m_Transform.getModelMatrix();
    m_Shader.setMat4("model", model);

    if(LeScene::getInstance()->getCurMouseHoverID() == m_GameObject->ID)
    {
        m_Shader.setVec4("color", 0.5, 0.5, 0.5, 0.5);
    }
    else
    {
        LeCubicSubBoxGameObject* pGO = dynamic_cast<LeCubicSubBoxGameObject*>(m_GameObject);
        m_Shader.setVec4("color", pGO->m_Color.x, pGO->m_Color.y, pGO->m_Color.z, pGO->m_Color.w);
    }

    // render the cube
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 36);
}

void LeCubicSubBoxRenderer::postLoopRender()
{
    glDeleteVertexArrays(1, &VAO);
}

void LeCubicSubBoxRenderer::renderSelection()
{
    // projection
    // ----------
//    glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
    glm::mat4 projection = glm::ortho(-4.0f, 4.0f,
                                      -3.0f, 3.0f,
                                      0.1f, 15.0f);
    // view
    // ----
//    LeCameraFlyBehaviour* pCameraBehaviour = dynamic_cast<LeCameraFlyBehaviour*>(LeCameraManager::pCameraObject->m_pCameraBehaviour);
    LeCameraCADBehaviour* pCameraBehaviour = dynamic_cast<LeCameraCADBehaviour*>(LeCameraManager::pCameraObject->m_pBehaviour);

    glm::vec3 camerafront = pCameraBehaviour->Front;
    glm::vec3 cameraup = pCameraBehaviour->Up;
    glm::vec3 cameraright = pCameraBehaviour->Right;

    float distanse2focus = 10;
    glm::vec3 focus = glm::vec3(0,0,0);
    glm::vec3 curCameraposition = focus - distanse2focus * camerafront;

    float offsetx = -2.1;
    float offsety = 2.1;
    glm::vec3 curOffsetCameraposition = curCameraposition + offsetx * cameraright + offsety * cameraup;

    glm::mat4 view = glm::lookAt(curOffsetCameraposition,
                                 curOffsetCameraposition + camerafront,
                                 cameraup);

    m_SelectionShader.useShader();
    m_SelectionShader.setMat4("projection", projection);
    m_SelectionShader.setMat4("view", view);

    glm::mat4 model = m_GameObject->m_Transform.getModelMatrix();
    m_SelectionShader.setMat4("model", model);

    m_SelectionShader.setInt("code", m_GameObject->ID);

    // render the cube
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 36);
}